package matlab;

import java.awt.image.BufferedImage;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;

import singleMain.singleMainclass;

import com.mathworks.toolbox.javabuilder.*;

import exception.MatlabException;
import exception.NoDefaultAlogrithmFoundException;

/**
 * Call matlab functions from here
 */
public class MatlabDriver {
	public static singleMainclass sm;
	public static BufferedImage queryRegion;
	public String queryPath;

	/**
	 * Constructor
	 */
	public MatlabDriver() {
	}
	
	public String getQueryPath() {
		return queryPath;
	}

	public void setQueryPath(String queryPath) {
		this.queryPath = queryPath;
	}

	public static BufferedImage getQueryRegion() {
		return queryRegion;
	}

	public static void setQueryRegion(BufferedImage queryRegion) {
		MatlabDriver.queryRegion = queryRegion;
	}

	/**
	 * Run the Region of interest with the matlab algorithms
	 * 
	 * @param algorithmName matlab
	 * @param path is the FILENAME of the image that contains the ROI
	 * @param region is array of locations that indicate the coordinates of the ROI
	 * @param savedResultPath 
	 * @throws MWException
	 * @throws NoDefaultAlogrithmFoundException
	 * @throws MatlabException 
	 */
	public void runROI(String algorithmName, String path, int[] region, String savedResultPath) throws MWException, NoDefaultAlogrithmFoundException, MatlabException {
		Object[] obj = new Object[3];
		obj[0] = path;
		obj[1] = region;
		obj[2] = savedResultPath;
		runMethod(algorithmName, "main", obj, obj.getClass());
		runMethod(algorithmName, "dispose", null, null); // 
	}

	/**
	 * Run matlab methods in matlab_algorithm.jar file 
	 * @param algorithmName contains matlab_algorithm.jar
	 * @param methodName
	 * @param args
	 * @param parameterTypes
	 * @throws NoDefaultAlogrithmFoundException
	 */
	private void runMethod(String algorithmName, String methodName,
			Object[] args, Class<?>... parameterTypes)
					throws NoDefaultAlogrithmFoundException, MatlabException {

		if (algorithmName.equals("") || algorithmName == null) {
			throw new NoDefaultAlogrithmFoundException();

		} else {
			try {

				if (!algorithmName.contains("."))
					algorithmName = algorithmName + ".jar";

				Class<?> cla = loadClass(algorithmName);
				Object obj = cla.newInstance();

				Method method;
				if (parameterTypes == null)
					method = cla.getDeclaredMethod(methodName, null);
				else
					method = cla.getDeclaredMethod(methodName, parameterTypes);
				if (args == null)
					method.invoke(obj, null);
				else
					method.invoke(obj, (Object) args);
			} catch (InstantiationException e) {
				System.out.println( e.getMessage() );
				throw new MatlabException( e.getMessage() );
			} catch (IllegalAccessException e) {
				System.out.println( e.getMessage() );
				throw new MatlabException( e.getMessage() );
			} catch (SecurityException e) {
				System.out.println( e.getMessage() );
				throw new MatlabException( e.getMessage() );
			} catch (NoSuchMethodException e) {
				System.out.println( e.getMessage() );
				throw new MatlabException( e.getMessage() );
			} catch (IllegalArgumentException e) {
				System.out.println( e.getMessage() );
				throw new MatlabException( e.getMessage() );
			} catch (InvocationTargetException e) {
				System.out.println( e.getMessage() );
				throw new MatlabException( e.getMessage() );
			}
		}
	}

	private Class<?> loadClass(String classname)
			throws NoDefaultAlogrithmFoundException, MatlabException {

		if (classname == null)
			throw new NoDefaultAlogrithmFoundException();
		else {
			File file = new File("./lib/mat/" + classname);
			URL[] urls = new URL[1];
			try {
				urls[0] = file.toURI().toURL();
			} catch (MalformedURLException e) {
				e.printStackTrace();
			}
			URLClassLoader child = new URLClassLoader(urls);
			try {
				String classloc = classname.substring(0,
						classname.lastIndexOf(".")); // classname =
				// test.jar
				// classloc =
				// test
				classloc = classloc + "." + classloc + "class";// classloc =
				// test.testclass

				Class<?> classToLoad = Class.forName(classloc, false, child);
				return classToLoad;
			} catch (ClassNotFoundException e) {
				System.out.println( e.getMessage() );
				throw new MatlabException( e.getMessage() );
			}
		}
	}

	// Deprecated ---------------------------------------
	public static singleMainclass getSm() throws MatlabException {

		try {
			sm = new singleMainclass();

		} catch (MWException e) {
			System.out.println( e.getMessage() );
			throw new MatlabException( e.getMessage() );
		}
		return sm;
	}

	public static void setSm(singleMainclass sm) {
		MatlabDriver.sm = sm;

	}
}
